﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Basmus.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Basmus.Tests.ResourcesTest
{
    [TestClass]
    public class StandartVirtualPathServiceTests
    {
        public const string NamespaceFirstPart = "Basmus";
        public const string NamespaceMiddlePart = "Tests";
        public const string NamespaceLastPart = "ResourcesTest";

        public class TestModel1 { }

        public class TestableStandartVirtualPathService : StandartVirtualPathService
        {
            public TestableStandartVirtualPathService(PathPartsResolvers resolvers, bool backslashed, bool replaceSlash) 
                : base(resolvers, backslashed, replaceSlash)
            {
            }
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootAtFirstPart()
        {
            // Arrange
            var ns = NamespaceFirstPart;
            var nsMap = new NamespaceMap().Add(ns, "root1/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof (TestModel1));

            // Assert
            var expected = string.Join("/", "root1/sub", NamespaceMiddlePart, NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootAtMiddlePart()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootAtLastPart()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart, NamespaceLastPart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "root2/sub", typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_Backslashed()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(true, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("\\", "root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootEndWithSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub/");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootStartWithSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "/root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "/root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootSurroundedWithSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "/root2/sub/");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "/root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_ReplaceSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, true);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_Backslashed_ReplaceSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "root2/sub");
            IVirtualPathService vpService = new StandartVirtualPathService(true, nsMap, true);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("\\", "root2\\sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootSurroundedWithSlash_ReplaceSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "/root2/sub/");
            IVirtualPathService vpService = new StandartVirtualPathService(false, nsMap, true);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("/", "/root2/sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_NoAttrs_RootSurroundedWithSlash_Backslashed_ReplaceSlash()
        {
            // Arrange
            var ns = string.Join(".", NamespaceFirstPart, NamespaceMiddlePart);
            var nsMap = new NamespaceMap().Add(ns, "/root2/sub/");
            IVirtualPathService vpService = new StandartVirtualPathService(true, nsMap, true);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            var expected = string.Join("\\", "\\root2\\sub", NamespaceLastPart, typeof(TestModel1).Name);
            Assert.AreEqual(expected, path);
        }

        [TestMethod]
        public void Resolve_FullPathAttr()
        {
            // Arrange
            var virtualPathServiceMock = new Mock<IVirtualPathService>();
            virtualPathServiceMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("root3/foo");

            var resolvers = new PathPartsResolvers { FullPathResolver = virtualPathServiceMock.Object, BasePathResolvers = new IPathResolver[] {} };
            IVirtualPathService vpService = new TestableStandartVirtualPathService(resolvers, false, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            Assert.AreEqual("root3/foo", path);
        }

        [TestMethod]
        public void Resolve_FullNameAttr_AnyBasePathResolver()
        {
            // Arrange
            var pathPesolverMock = new Mock<IPathResolver>();
            pathPesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("some_path/part2");
            var fullNamePesolverMock = new Mock<IFullNameResolver>();
            fullNamePesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("this_is_fullname.aspx");

            var resolvers = new PathPartsResolvers
                                {
                                    FullPathResolver = new Mock<IVirtualPathService>().Object,
                                    BasePathResolvers =
                                        new[] { new Mock<IPathResolver>().Object, pathPesolverMock.Object, new Mock<IPathResolver>().Object, },
                                    FullNameResolver = fullNamePesolverMock.Object
                                };

            IVirtualPathService vpService = new TestableStandartVirtualPathService(resolvers, false, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            Assert.AreEqual("some_path/part2/this_is_fullname.aspx", path);
        }

        [TestMethod]
        public void Resolve_NameAttr_AnyBasePathResolver()
        {
            // Arrange
            var pathPesolverMock = new Mock<IPathResolver>();
            pathPesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("some_path/part2");
            var namePesolverMock = new Mock<INameResolver>();
            namePesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("name_dddddd");

            var resolvers = new PathPartsResolvers
                                {
                                    FullPathResolver = new Mock<IVirtualPathService>().Object,
                                    BasePathResolvers =
                                        new[] { new Mock<IPathResolver>().Object, pathPesolverMock.Object, new Mock<IPathResolver>().Object, },
                                    FullNameResolver = new Mock<IFullNameResolver>().Object,
                                    NameWithoutExtensionResolver = namePesolverMock.Object,
                                    ExtensionResolver = new Mock<IExtensionResolver>().Object
                                };

            IVirtualPathService vpService = new TestableStandartVirtualPathService(resolvers, false, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            Assert.AreEqual("some_path/part2/name_dddddd", path);
        }

        [TestMethod]
        public void Resolve_ExtensionAttr_AnyBasePathResolver()
        {
            // Arrange
            var pathPesolverMock = new Mock<IPathResolver>();
            pathPesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns("some_path/part2");
            var extensionPesolverMock = new Mock<IExtensionResolver>();
            extensionPesolverMock.Setup(x => x.Resolve(It.IsAny<Type>())).Returns(".proj");

            var resolvers = new PathPartsResolvers
            {
                FullPathResolver = new Mock<IVirtualPathService>().Object,
                BasePathResolvers =
                    new[] { new Mock<IPathResolver>().Object, pathPesolverMock.Object, new Mock<IPathResolver>().Object, },
                FullNameResolver = new Mock<IFullNameResolver>().Object,
                NameWithoutExtensionResolver = new Mock<INameResolver>().Object,
                ExtensionResolver = extensionPesolverMock.Object
            };

            IVirtualPathService vpService = new TestableStandartVirtualPathService(resolvers, false, false);

            // Act
            var path = vpService.Resolve(typeof(TestModel1));

            // Assert
            Assert.AreEqual("some_path/part2/.proj", path);
        }
    }
}
